home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Turnbull China Bikeride
/
Turnbull China Bikeride - Disc 2.iso
/
STUTTGART
/
LANG
/
C
/
LIB
/
UNIXLIB37B
/
!UnixLib37
/
src
/
signal
/
c
/
post
< prev
next >
Wrap
Text File
|
1996-11-09
|
10KB
|
351 lines
/****************************************************************************
*
* $Source: /unixb/home/unixlib/source/unixlib37/src/signal/c/RCS/post,v $
* $Date: 1996/11/06 22:01:42 $
* $Revision: 1.2 $
* $State: Rel $
* $Author: unixlib $
*
* $Log: post,v $
* Revision 1.2 1996/11/06 22:01:42 unixlib
* Yet more changes by NB, PB and SC.
*
* Revision 1.1 1996/10/30 22:04:51 unixlib
* Initial revision
*
***************************************************************************/
static const char rcs_id[] = "$Id: post,v 1.2 1996/11/06 22:01:42 unixlib Rel $";
/* signal.c.post: Written by Nick Burrett, 27 August 1996. */
#include <stdlib.h>
#include <signal.h>
#include <stdio.h>
#include <errno.h>
#include <sys/wait.h>
#include <sys/os.h>
#include <sys/unix.h>
#include <unixlib/sigstate.h>
/* #define DEBUG */
void
__unixlib_default_sigaction (struct unixlib_sigstate *ss)
{
int signo;
sigemptyset (&ss->actions[0].sa_mask);
ss->actions[0].sa_flags = SA_RESTART;
ss->actions[0].sa_handler = SIG_DFL;
/* Set all signals to their defaults. */
for (signo = 1; signo < NSIG; ++signo)
ss->actions[signo] = ss->actions[0];
}
void __unixlib_internal_post_signal (struct unixlib_sigstate *ss,
int signo, int sigcode, int sigerror)
{
enum { stop, ignore, core, term, handle } act;
__sighandler_t handler;
struct unixlib_signal_preempt *pe;
sighandler_t (*preempt) (int, int, int) = NULL;
sigset_t pending;
int ss_suspended;
post_signal:
#ifdef DEBUG
printf ("__unixlib_internal_post_signal: sigstate = %x, signo = %d\n", (int)ss, signo);
#endif
/* Increment the number of signals this process has received. */
__u->usage.ru_nsignals++;
/* Support for pre-emptive handlers. */
for (pe = __u->sigpreempt[signo]; pe != NULL; pe = pe->next)
if (sigcode >= pe->first && sigcode <= pe->last)
{
preempt = pe->handler;
break;
}
handler = SIG_DFL;
if (preempt)
{
/* Let the preempting handle examine the thread.
If it returns SIG_DFL, we run the normal handler;
otherwise we use the handler it returns. */
#ifdef DEBUG
os_print ("\r\n__unixlib_internal_post_signal: running a signal pre-empter\r\n");
#endif
handler = (*preempt) (0, signo, sigcode);
}
ss_suspended = 0;
#ifdef DEBUG
printf ("__unixlib_internal_post_signal: Do the handling\n");
#endif
if (handler != SIG_DFL)
/* Run the preemption-provided handler. */
act = handle;
else
{
/* Do normal handling. */
handler = ss->actions[signo].sa_handler;
#ifdef DEBUG
printf ("__unixlib_internal_post_signal: handler = %x\n", (int)handler);
#endif
if (handler == SIG_DFL)
/* Figure out the default action for this signal. */
switch (signo)
{
case 0:
/* Special signo used for posting any pending signals. */
act = ignore;
break;
case SIGTTIN:
case SIGTTOU:
case SIGSTOP:
case SIGTSTP:
/* Signals that will stop a process. */
act = stop;
break;
case SIGCONT:
case SIGIO:
case SIGURG:
case SIGCHLD:
case SIGWINCH:
/* Signals that can otherwise be ignored. */
act = ignore;
break;
case SIGQUIT:
case SIGILL:
case SIGTRAP:
case SIGIOT:
case SIGEMT:
case SIGFPE:
case SIGBUS:
case SIGSEGV:
case SIGSYS:
/* Fatal signals that will cause a core dump. */
act = core;
break;
case SIGINFO:
if (__u->pgrp == __u->pid)
{
/* We provide a default handler for SIGINFO since
there is no user-specified handler. */
act = handle;
handler = __unixlib_siginfo_handler;
}
else
act = ignore;
break;
default:
/* All other signals will cause a process termination. */
act = term;
break;
}
else if (handler == SIG_IGN)
act = ignore;
else
act = handle;
if (sigmask (signo) & (sigmask (SIGTTIN) | sigmask (SIGTTOU)
| sigmask (SIGSTOP) | sigmask (SIGTSTP)))
/* Stop signals clear a pending SIGCONT even if they
are handled or ignored (but not if preempted). */
sigdelset (&ss->pending, SIGCONT);
else if (signo == SIGCONT)
{
/* Even if handled or ignored (but not preempted),
SIGCONT clears stop signals and resumes the process. */
sigdelset (&ss->pending, SIGTTIN);
sigdelset (&ss->pending, SIGTTOU);
sigdelset (&ss->pending, SIGSTOP);
sigdelset (&ss->pending, SIGTSTP);
/* Resume all our children. */
ss_suspended = 1;
__u->status.stopped = 0;
}
}
#ifdef DEBUG
printf ("__unixlib_internal_post_signal: act = %d\n", act);
#endif
if (__u->orphaned && act == stop &&
(signo & (sigmask (SIGTTIN) | sigmask (SIGTTOU) | sigmask (SIGTSTP))))
{
/* If we would ordinarily stop for a job control signal, but we are
orphaned so noone would ever notice and continue us again, we just
quietly die, alone and in the dark. */
sigcode = signo;
signo = SIGKILL;
act = term;
}
/* Handle a blocked signal. */
if ((sigismember (&ss->blocked, signo) && act != ignore)
|| (signo != SIGKILL && __u->stopped))
{
sigaddset (&ss->pending, signo);
/* Save the code to be given to the handler when SIGNO is unblocked. */
ss->pending_data[signo].code = sigcode;
ss->pending_data[signo].error = sigerror;
act = ignore;
}
#ifdef DEBUG
printf ("__unixlib_internal_post_signal: Do the chosen action\n");
#endif
/* Perform the chosen action for the signal. */
switch (act)
{
case stop:
#ifdef DEBUG
printf ("__unixlib_internal_post_signal: stop\n");
#endif
if (! __u->status.stopped)
{
/* Stop all our threads, and mark ourselves stopped. */
__u->status.stopped = 1;
}
/* Wake up sigsuspend. */
sigwakeup ();
break;
case ignore:
#ifdef DEBUG
printf ("__unixlib_internal_post_signal: ignore\n");
#endif
/* Nobody cares about this signal. */
break;
case term: /* Time to die. */
case core: /* and leave a rotting corpse. */
death:
/* Stop all other threads in our task. */
/* No more user instructions wil be executed. */
{
int status = W_EXITCODE (0, signo);
/* Do a core dump if desired. Only set the wait status bit saying
we in fact dumped core if the operation was actually successful. */
#ifdef DEBUG
printf ("__unixlib_internal_post_signal: term/core\n");
#endif
if (act == term)
__write_termination (signo, sigcode, sigerror);
else if (act == core && __write_corefile (signo, sigcode, sigerror))
status |= WCOREFLAG;
/* Die, returning information about how we died. */
_exit (status);
/* Never reached. */
}
break;
case handle:
/* Call a handler for this signal. */
{
sigset_t blocked;
int flags;
#ifdef DEBUG
printf ("__unixlib_internal_post_signal: handle\n");
#endif
/* We're going to handle this signal now, so remove it from
the pending list. */
sigdelset (&ss->pending, signo);
/* Block SIGNO and requested signals while running the handler. */
blocked = ss->blocked;
ss->blocked |= sigmask (signo) | ss->actions[signo].sa_mask;
flags = ss->actions[signo].sa_flags;
/* Re-instate the default signal handler. We do this before executing
the signal handler because a new handler might be setup whilst
executing the signal handler. */
ss->actions[signo].sa_handler = SIG_DFL;
ss->actions[signo].sa_flags = SA_RESTART;
sigemptyset (&ss->actions[signo].sa_mask);
/* Call the function to set the thread up to run the signal
handler, and preserve its old context. */
if (__unixlib_setup_sighandler (ss, handler, signo, sigcode, flags))
{
/* We got a fault setting up the stack frame for the handler.
Nothing to do but die. */
sigcode = signo;
signo = SIGILL;
act = core;
goto death;
}
/* If we reach here, we have successfully executed the signal handler.
All that is left is to restore the defaults. */
/* Re-instate the original sigset. */
ss->blocked = blocked;
break;
}
}
#ifdef DEBUG
printf ("__unixlib_internal_post_signal: Deliver pending signals\n");
#endif
/* Deliver pending signals. */
if (!__u->stopped && (pending = ss->pending & ~ss->blocked))
{
for (signo = 1; signo < NSIG; ++signo)
if (sigismember (&pending, signo))
{
sigdelset (&ss->pending, signo);
sigcode = ss->pending_data[signo].code;
sigerror = ss->pending_data[signo].error;
goto post_signal;
}
}
ss->currently_handling = 0;
/* No more signals pending. */
sigwakeup ();
}
void __unixlib_raise_signal (struct unixlib_sigstate *ss,
int signo, int sigcode, int sigerror)
{
if (ss == NULL)
ss = &__u->sigstate;
/* Mark signo as pending to be delivered. */
sigaddset (&ss->pending, signo);
ss->pending_data[signo].code = sigcode;
ss->pending_data[signo].error = sigerror;
if (!ss->currently_handling)
{
/* Post the signal if we are not already handling a signal. */
ss->currently_handling = 1;
__unixlib_internal_post_signal (ss, signo, sigcode, sigerror);
}
#ifdef DEBUG
else
{
os_print ("\n\r__unixlib_raise_signal: signal ");
os_print (sys_siglist[signo]);
os_print (" is pending for delivery\r\n");
}
#endif
}